package br.com.fpf.pontoapp.model.db.impl;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.MessageFormat;

import roboguice.util.Ln;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import br.com.fpf.pontoapp.model.db.IPontoDB;

import com.google.inject.Inject;
import com.google.inject.Singleton;

/**
 * Responsible for manipulating the database.
 */
@Singleton
public final class PontoDB extends SQLiteOpenHelper implements IPontoDB {

	/** The Constant COMMENT. */
	private static final String COMMENT = "--";

	/** The Constant DATABASE_NAME. */
	private static final String DATABASE_NAME = "opontofpf";

	/** The Constant DB_SQL. */
	private static final String DB_SQL = "db.sql";

	/** The Constant REG_EXPRESSION. */
	private static final String REG_EXPRESSION = ";";

	/** The Constant DATABASE_VERSION. */
	private static final int DATABASE_VERSION = 1;

	/** The context. */
	private final Context context;

	/**
	 * Constructor.
	 * 
	 * @param androidContext
	 *            of the application
	 */
	@Inject
	public PontoDB(final Context androidContext) {
		super(androidContext, DATABASE_NAME, null, DATABASE_VERSION);
		this.context = androidContext;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * android.database.sqlite.SQLiteOpenHelper#onCreate(android.database.sqlite
	 * .SQLiteDatabase)
	 */
	@Override
	public void onCreate(final SQLiteDatabase sqlitedb) {
		executeSQL(getStatementSql(DB_SQL), sqlitedb);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * android.database.sqlite.SQLiteOpenHelper#onUpgrade(android.database.sqlite
	 * .SQLiteDatabase, int, int)
	 */
	@Override
	public void onUpgrade(final SQLiteDatabase sqlitedb, final int oldVersion,
			final int newVersion) {
		dropTables(sqlitedb);
		onCreate(sqlitedb);
	}

	/**
	 * Drop tables.
	 * 
	 * @param sqlitedb
	 *            the sqlitedb
	 */
	private void dropTables(final SQLiteDatabase sqlitedb) {
		for (final Table table : Table.values()) {
			executeSQL(
					MessageFormat.format("DROP TABLE IF EXISTS {0}",
							table.getName()), sqlitedb);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * br.com.fpf.pontoapp.model.db.IPontoDB#executeSQLFile(java.lang.String)
	 */
	public void executeSQLFile(final String fileName) {
		executeSQL(getStatementSql(fileName));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see br.com.fpf.pontoapp.model.db.IPontoDB#executeSQL(java.lang.String[])
	 */
	public void executeSQL(final String[] sqls) {
		executeSQL(sqls, getDatabase());
	}

	/**
	 * Executes a list of sql commands to the database passed by parameter.
	 * 
	 * @param sqls
	 *            the sqls
	 * @param sqlitedb
	 *            database that will be executed
	 */
	private void executeSQL(final String[] sqls, final SQLiteDatabase sqlitedb) {
		for (final String sql : sqls) {
			if (sql != null && !sql.isEmpty()) {
				sqlitedb.execSQL(sql);
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see br.com.fpf.pontoapp.model.db.IPontoDB#executeSQL(java.lang.String)
	 */
	public void executeSQL(final String sql) {
		executeSQL(sql, getDatabase());
	}

	/**
	 * Execute a sql command in database parameter passed.
	 * 
	 * @param sql
	 *            to be executed
	 * @param sqlitedb
	 *            database that will be executed
	 */
	private void executeSQL(final String sql, final SQLiteDatabase sqlitedb) {
		sqlitedb.execSQL(sql);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * br.com.fpf.pontoapp.model.db.IPontoDB#getStatementSql(java.lang.String)
	 */
	public String[] getStatementSql(final String fileName) {
		final StringBuilder stringBuilder = new StringBuilder();
		InputStream inputStream;
		BufferedReader sqlFile = null;
		try {
			inputStream = context.getAssets().open(fileName);
			final InputStreamReader reader = new InputStreamReader(inputStream);
			sqlFile = new BufferedReader(reader);
			String buff = sqlFile.readLine();

			while (buff != null) {
				if (!buff.trim().startsWith(COMMENT)) {
					stringBuilder.append(buff);
				}
				buff = sqlFile.readLine();
			}

		} catch (final IOException e) {
			Ln.d(e);
		} finally {
			if (sqlFile != null) {
				try {
					sqlFile.close();
				} catch (final IOException e) {
					Ln.d(e);
				}
			}
		}

		return stringBuilder.toString().split(REG_EXPRESSION);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see br.com.fpf.pontoapp.model.db.IPontoDB#getDatabase()
	 */
	public SQLiteDatabase getDatabase() {
		return getWritableDatabase();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see br.com.fpf.pontoapp.model.db.ITransactionSupport#beginTransaction()
	 */
	@Override
	public void beginTransaction() {
		getDatabase().beginTransaction();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see br.com.fpf.pontoapp.model.db.ITransactionSupport#endTransaction()
	 */
	@Override
	public void endTransaction() {
		getDatabase().endTransaction();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see br.com.fpf.pontoapp.model.db.ITransactionSupport#setSuccessfull()
	 */
	@Override
	public void setSuccessfull() {
		getDatabase().setTransactionSuccessful();
	}

}
